# -*- mode: python; coding: utf-8; -*-
##---------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##---------------------------------------------------------------------------##
"""
Stat Viewer for tile/tk.
"""
__docformat__ = "restructuredtext en"
#_ = lambda x: x

import Tkinter
import ttk
import tkFont
import tkSimpleDialog
from Tkinter import ACTIVE, LEFT

#from .npsevent import bind
from ...utillib.cache import IMAGE_CACHE
from ...statdb import STAT_DB
from ...utillib.misc import format_time
from ...settings import CONF_OPT
from ...statform import StatsFormatter, ProgressionFormatter

#: (Win | Lost, Play | Average | Shadow | Highlight, None )
#  COLOR OPTIONS: http://www.tcl.tk/man/tcl8.5/TkCmd/colors.htm
COLORPALLETE = ('ForestGreen', 'FireBrick', 'MidnightBlue', 'DarkSlateGrey',
                'AntiqueWhite')


def _percent(won, lost):
    """
    _percent(won:int, lost:int) -> seq(float, float)

    Returns percentage won and lost.
    """
    percent = lambda w, t: float(w) / t if t else 0.0
    pwon = percent(won, won + lost)
    return pwon, 1.0 - pwon


class StatsViewer(tkSimpleDialog.Dialog):
    """
    Stat Viewer

    Show dialog with embedded notebook with 4 tab frames.

      - Session: Show statistics for this and past sessions.
      - Full:  Show statistics all games and sessions played.
      - Game:  Show statistics for this and past games.
      - Progress:  Show progress for all games played.
    """
    __tabs = []
    _selected = None
    _buttons = {}
    mode = -1
    gameid = -1

    def __init__(self, parent, player, gameid):
        """
        __init__(parent:Canvas, player:str, gameid:int) -> None

        Set gameid and player from passed values. Set header and normal fonts.
        Call its parent method in **Dialog**.
        """
        self._gameid = gameid
        self._player = player or _("Demo games")

        style = ttk.Style(parent)
        self.tkfont = tkFont.Font(parent, style.lookup('.',  'font'))
        self.tkfont_ls = self.tkfont.metrics()['linespace']
        style = ttk.Style(parent)
        self.tkheadfont = tkFont.Font(parent, style.lookup('Heading', 'font'))

        tkSimpleDialog.Dialog.__init__(self, parent, _('Game Summary'))

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Create tabs for current session, all sessions, current game, and
        progress details.
        """
        notebook = ttk.Notebook(parent)
        notebook.pack(expand=True, fill='both', padx=10, pady=10)

        for obj in (_SessionsFrame, _AllFrame, _GamesFrame, ):
            pframe = obj(self, notebook)
            notebook.add(pframe, text=pframe.tabTitle)
            self.__tabs.append(pframe._w)

        if self._player is not _("Demo games"):
            progr_frame = _ProgressFrame(self, notebook)
            notebook.add(progr_frame, text=_('Progress Summary'))
            self.__tabs.append(progr_frame._w)

        self._notebook = notebook
        self._notebook.bind('<<NotebookTabChanged>>', self.__tab_changes)

    def buttonbox(self):
        """
        buttonbox(self) -> None

        Overide standard button box with buttons for game select, dialog cancel,
        and stat reser. Sets button state for game select and stat reset.
        """
        box = ttk.Frame(self)

        select_bttn = ttk.Button(box, text=_("Select Game"), width=10,
                                   command=self.ok)
        select_bttn.pack(side=LEFT, padx=4, pady=4)
        self._buttons['select'] = select_bttn

        save_bttn = ttk.Button(box, text=_("Save Stats"), width=10,
                                   command=self.save)
        save_bttn.pack(side=LEFT, padx=4, pady=4)
        self._buttons['save'] = save_bttn

        cancel_bttn = ttk.Button(box, text=_("Cancel"), width=10,
                                   command=self.cancel, default=ACTIVE)
        cancel_bttn.pack(side=LEFT, padx=4, pady=4)

        reset_bttn = ttk.Button(box, text=_("Reset"), width=10,
                                   command=self._reset)
        reset_bttn.pack(side=LEFT, padx=4, pady=4)
        self._buttons['reset'] = reset_bttn

        self.bind("<Return>", self.cancel)
        self.bind("<Escape>", self.cancel)

        box.pack()

        self.__tab_changes()

    def __tab_changes(self, *args):
        """
        __tab_changes(self, *args)

        Sets button state for game select and stat reset.
        """
        if not hasattr(self, '_buttons'):
            return

        tab = self.__tabs.index(self._notebook.select())
        # Control of Select button
        self._buttons['select'].config(state='disabled')

        # Control of Reset button
        self._buttons['reset'].config(state='disabled'
                                      if tab in (0, 3) else 'normal')

        # Control of Save button
        self._buttons['save'].config(state='disabled'
                                      if not tab == 1 else 'normal')

    def apply(self):
        """
        apply() -> None

        Set **self.mode** for a new game with selected.
        """
        self.mode = 401
        self.gameid = self._selected

    def save(self):
        """
        apply() -> None

        Set **self.mode** for a save summary.
        """
        tab = self.__tabs.index(self._notebook.select())
        assert tab == 1
        self.mode = 202
        self.destroy()

    def _reset(self):
        """
        reset() -> None

        Set **self.mode** for a stat reset of either current or all sessions.
        """
        tab = self.__tabs.index(self._notebook.select())
        assert tab in [0, 2]
        self.mode = 302 if tab == 0 else 301
        self.destroy()


class _SessionsFrame(ttk.Frame):
    """
    Show current game average summary
    """
    tabTitle = _('Session Summary')
    sec_titles = (_("This session"), _("All sessions"), )
    tabImg = ['logos', 'joker11_100_774']
    __cw, __ch = 120, 60
    __chart = {True: None, False: None}
    __text = {True: [], False: []}

    def __init__(self, dialog, parent):
        """
        __init__(dialog:ChildDialog, parent:Canvas)
          -> None

        Create frame with detail as two pie charts for current game in this and
        all sessions. Call its parent method in **Frame**.
        """
        assert hasattr(dialog, '_player') and hasattr(dialog, '_gameid')
        self.__chart = {True: None, False: None}
        self.__text = {True: [], False: []}
        ttk.Frame.__init__(self, parent)
        ttk.Label(self, image=IMAGE_CACHE.load(*self.tabImg)).pack(side='left',
                                                     expand=True, fill='both')
        frame = ttk.Frame(self)
        frame.pack(side='right', expand=True)

        # Create tables
        self.dialog = dialog
        for value, title in zip((False, True), self.sec_titles):
            iframe = ttk.LabelFrame(frame, text=title)
            self._create_chart(iframe, value)
            self._create_texts(iframe, value)
            iframe.pack(side='top', fill='both', expand=False, padx=20, pady=10)

    def _create_texts(self, parent, all_):
        """
        __create_texts(parent:Canvas, all_:bool) -> None

        Create chart text fields with titles. Store label fields for updating.
        Call update texts to add values.
        """
        for i, ttl in enumerate([_("Success:"), _("Failure:"), _("Total:")]):
            ttk.Label(parent, text=ttl, font=self.dialog.tkheadfont).grid(
                                                 row=i, column=1, sticky='ne')
            val = ttk.Label(parent, text='')
            val.grid(row=i, column=2, sticky='nw')
            avg = ttk.Label(parent, text='')
            avg.grid(row=i, column=3, sticky='nw')
            self.__text[all_].append((val, avg, ))
        self._update_texts(all_)

    def _update_texts(self, all_):
        """
        _update_texts(all_:bool) -> None

        Update a chart text fields with data from **STAT_DB** for **player**
        and **gameid**.
        """
        dialog = self.dialog
        won, lost = STAT_DB.basic(dialog._player, dialog._gameid, all_)
        total = won + lost
        pwon, plost = _percent(won, lost)
        for row, (val, avg) in enumerate([(won, '{:.2%}'.format(pwon),),
                                          (lost, '{:.2%}'.format(plost),),
                                          (total, '', )]):
            value_label, average_label = self.__text[all_][row]
            if total > 0:
                # Games have some wins and losses
                value_label.config(text=val)
                value_label.grid(row=row, column=2, sticky='nw')
                average_label.config(text=avg)
                average_label.grid(row=row, column=3, sticky='nw')
            else:
                # Games are unplayed
                value_label.config(text=_('no games played'))
                #v.grid(row=i, column=2, columnspan=2, sticky='n')
                average_label.config(text='')

    def _create_chart(self, parent, all_):
        """
        __create_chart(parent:Canvas, all_:bool) -> None

        Create chart pie graph form. Call update chart to add values.
        """
        self._cnvs = Tkinter.Canvas(parent, width=self.__cw, height=self.__ch)
        self._cnvs.pack(side='left', fill='both', expand=True)
        self._cnvs.grid(row=0, column=0, rowspan=3)
        self._cnvs.create_oval(20, 15, self.__cw - 20, self.__ch - 5,  # Shadow
                           fill=COLORPALLETE[3])
        self._update_chart(all_)

    def _update_chart(self, all_):
        """
        _update_chart(all_:bool) -> None

        Update a chart pie graph with data from **STAT_DB** for **player**
        and **gameid**. Store graphs for updating.
        """
        if self.__chart[all_] is not None:
            for item in self.__chart[all_]:
                self._cnvs.delete(item)

        dialog = self.dialog
        won, lost = STAT_DB.basic(dialog._player, dialog._gameid, all_)
        fill = 4  # Unplayed color index
        if won + lost > 0:
            pwon, plost = _percent(won, lost)

            if 0 not in [lost, won]:
                cwidth, cheight = self.__cw - 20, self.__ch - 10
                self.__chart[all_] = (
                    # percent games won
                    self._cnvs.create_arc(20, 10, cwidth, cheight,
                                          fill=COLORPALLETE[0], start=0.0,
                                          extent=360.0 * pwon),
                    # percent games lost
                    self._cnvs.create_arc(20, 10, cwidth, cheight,
                                          fill=COLORPALLETE[1],
                                          start=360.0 * pwon,
                                          extent=360.0 * plost),)
                return
            # Games have only wins or losses
            fill = lost is not 0

        self.__chart[all_] = (
            # only win, loss, or no stat for game. **fill** set accordingly.
            self._cnvs.create_oval(20, 10, self.__cw - 20, self.__ch - 10,
                                   fill=COLORPALLETE[fill]),)


class _AllFrame(ttk.Frame, StatsFormatter):
    """
    Show total game average summary
    """
    tabTitle = _('Full Summary')
    colRefIds = ('#0', 'played', 'won', 'lost', 'time', 'moves', 'percent')
    colTitles = (_('Game'), _('Total'), _('Success'), _('Failure'), _('Time'),
             _('Moves'), _('Rate'))
    MAX_ROWS = 999
    __sort = 'name'
    __tabs = None
    __items = {}

    def __init__(self, dialog, parent):
        """
        __init__(dialog:ChildDialog, parent:Canvas)
          -> None

        Create frame with detail as list of game's played with averages. Call
        its parent methods in **Frame** and **StatsFormatter**.
        """
        assert hasattr(dialog, '_player') and hasattr(dialog, '_gameid')
        ttk.Frame.__init__(self, parent)

        StatsFormatter.__init__(self, dialog._player, dialog._gameid)
        self.dialog = dialog

        self.__tree = ttk.Treeview(self, columns=self.colRefIds[1:],
                                   selectmode='browse')
        self.__tree.grid(row=0, column=0)

        vsb = ttk.Scrollbar(self, command=self.__tree.yview)
        vsb.grid(row=0, column=1, sticky='ns')
        self.__tree.config(yscrollcommand=vsb.set)

        self._create_header()
        self._create_footer(self)

        self.__tree.bind('<<TreeviewSelect>>', self._selection)
        self.__tree.bind('<Map>', self._populate)

    def _selection(self, *args):
        """
        _select(*args) -> None

        Set **selected** value and enable **select_bttn** in parent dialog.
        The **select_bttn** is enabled only when valid selection has been made.
        """
        dialog = self.dialog
        assert hasattr(dialog, '_selected') and hasattr(dialog, '_play_bttn')
        sel = self.__tree.selection()
        item = (self.__items.get(sel[0], None) if sel and len(sel) == 1
                                              else None)
        dialog._selected = item
        dialog._buttons['select'].config(state='disabled' if item is None
                                                          else 'normal')

    def _sort_cols(self, column):
        """
        _sort_cols(column:str) -> None

        Set new sort and unset current list if sort is different. Call
        populate to rebuild the list.
        """
        sort = 'name' if column == '#0' else column
        if self.__sort != sort:
            self.__sort = sort

            if len(self.__items) > 0:
                self.__tree.delete(*self.__items)
                self.__items = {}

            self.__populate()

    def _create_header(self):
        """
        _create_header() -> None

        Size columns and set header for list.
        """
        if self.__tabs is None:
            self.__tabs = [300]
            self.__tabs.extend(self.dialog.tkheadfont.measure(t) + 8
                               for t in self.colTitles[1:])

        for i, (col, ttl) in enumerate(zip(self.colRefIds, self.colTitles)):
            self.__tree.column(col, width=self.__tabs[i], anchor='e')
            self.__tree.heading(col, text=ttl,
                                      command=lambda c=col: self._sort_cols(c))

    def _create_footer(self, frame):
        """
        self.__createFooter(frame:ttk.Frame) => None

        Display games played to games available from **StatsFormatter** parent
        below the list view.
        """
        # seq(total, played, ...)
        summary = self.getSummary()
        ttk.Label(frame,
             text=_('{0[1]} games have been played of {0[0]} available.'
                    ).format(summary)).grid(row=1, column=0, columnspan=2,
                                            sticky='ne')

    def _populate(self, *args):
        """
        self._populate(*args) => None

        Populate list view with **StatsFormatter** data. Include query result
        and summary in list view.
        """
        dialog = self.dialog
        assert hasattr(dialog, '_selected')
        assert hasattr(dialog, '_buttons') and 'select' in dialog._buttons
        if len(self.__items) > 0:
            return

        # Insert StatsFormatter results
        for result in self.getResults(self.__sort):
            #{ [name, played, won, lost, time, moves, average, gid]
            id_ = self.__tree.insert("", "end", text=result[0],
                                    values=result[1:-1])
            self.__items[id_] = result[7]

        # Insert StatsFormatter summary
        # seq(total, played, won, lost, time_, moves, perc)
        summary = self.getSummary()
        id_ = self.__tree.insert("", "end", text=("Game Play Summary"),
                               values=[sum(summary[2:4])] + list(summary[2:]),
                               tags=('total', ))
        self.__tree.tag_configure('total', font=self.dialog.tkheadfont)
        self.__items[id_] = None

        dialog._selected = -1
        dialog._buttons['select'].config(state='disabled')


class _GamesFrame(ttk.Frame):
    """
    Show current game stat summary.
    """
    tabTitle = _("Game Summary")
    secTitles = (_('This game'), _('All games'), )
    tabImg = ['logos', 'joker11_100_774']

    def __init__(self, dialog, parent):
        """
        __init__(dialog:ChildDialog, parent:Canvas)
          -> None

        Create frame with detail as fields of game stat summary. Call its parent
        methods in **Frame**.
        """
        assert hasattr(dialog, '_player') and hasattr(dialog, '_gameid')
        ttk.Frame.__init__(self, parent)

        ttk.Label(self, image=IMAGE_CACHE.load(*self.tabImg)).pack(side='left',
                                                     expand=True, fill='both')

        frame = ttk.Frame(self)
        frame.pack(side='right', expand=True)

        # Create tables
        self.dialog = dialog
        for value, title in zip((False, True), self.secTitles):
            self._create_texts(frame, title, value)

    def _create_texts(self, parent, title, all_):
        """
        __create_texts(parent:Canvas, title:str, all_:bool) -> None

        Create summary table with field titles.
        """
        from datetime import timedelta
        dialog = self.dialog
        frame = ttk.LabelFrame(parent, text=title)

        # Create column headers
        for col, title in enumerate([_('Min'), _('Max'), _('Avg'),
                                     _('Total')], 1):
            ttk.Label(frame, text=title, font=dialog.tkheadfont).grid(row=0,
                                                                     column=col)
        for row, (title, values) in enumerate(STAT_DB.summary(dialog._player,
                                              'all' if all_ else dialog._gameid,
                                              ).items(), 1):
            # Create row headers
            ttk.Label(frame, text=title, font=dialog.tkheadfont).grid(row=row,
                                                                      column=0)
            if values in ([0] * 5, [timedelta(0)] * 5, ):
                ttk.Label(frame, text=_('No games played')).grid(row=row,
                                                         column=1, columnspan=3)
            else:
                for col, value in enumerate(values[:-1], 1):
                    if type(value) is timedelta:
                        value = format_time(value)
                    else:
                        value = (round(value, 2) if type(value) == float
                                                 else value)
                    ttk.Label(frame, text=value).grid(row=row, column=col)

        frame.pack(side='top', fill='both', expand=False, padx=20, pady=10)


class _ProgressFrame(ttk.Frame, ProgressionFormatter):
    """
    Game progress frame
    """
    cname = (_('Played'), _('Won'), _('Average'), )          # Chart names
    sname = (_('All games'), _('This game'), )               # Scope names
    dname = (_('Last week'), _('Last month'), _('Last year'),
             _('Since start'), )                             # Duration names
    tname = (_('Games'), _('Average'))  # Title names
    _vars = {}
    __cw, __ch = 500, 200
    __items = []

    def __init__(self, dialog, parent):
        """
        __init__(dialog:ChildDialog, parent:Canvas)
          -> None

        Create frame with progress chart for game. Call its parent methods in
        **Frame** and **ProgressionFormatter**.
        """
        assert hasattr(dialog, '_player') and hasattr(dialog, '_gameid')

        ttk.Frame.__init__(self, parent)
        ProgressionFormatter.__init__(self, dialog._player, dialog._gameid)

        self.dialog = dialog

        textwidth = max(self.dialog.tkfont.measure(t) for t in self.tname)
        self.__th = self.dialog.tkfont_ls
        self.__lm = 10 + textwidth / 2
        self.__rm = self.__cw - self.__lm
        self.__tm = 10 + self.__th
        self.__bm = self.__ch - self.__tm

        # create canvas
        self.canvas = Tkinter.Canvas(self, width=self.__cw, height=self.__ch)
        self.canvas.pack(side='top')
        self._create_controls(self)

        self.canvas.bind('<Map>', self._create_chart)

    def _create_controls(self, frame):
        """
        _create_controls(self, frame)

        Create the chart controls for scope, duration, charts.
        """

        def set_value(type_, name, value):
            """
            set_value(type_:str, name:str, value:str) -> None

            Set **name** with Tkinter **type_**  of **value**.
            """
            vtype = getattr(Tkinter, "{}Var".format(type_))
            self._vars[name] = vtype()
            self._vars[name].set(value)

        def radio_widget(frame, title, name, values):
            """
            radio_widget(frame:Canvas, title:str, name:str, values:seq(str ...))
              -> None

            Create frame of **title** with set radio widgets for **values**.
            """
            frame = ttk.LabelFrame(frame, text=title, padding=(10, 5, 10, 10))
            for idx, (value, title) in enumerate(values):
                bttn = ttk.Radiobutton(frame, text=title, command=self._update,
                                    variable=self._vars[name], value=value)
                bttn.grid(row=idx % 2, column=idx - (idx % 2), sticky="nw")
            frame.pack(side='left', padx=10, pady=10)

        def check_widget(frame, title, values):
            """
            check_widget(frame:Canvas, title:str, name:str, values:seq(str ...))
              -> None

            Create frame of **title** with set checkbox widgets for **values**.
            """
            frame = ttk.LabelFrame(frame, text=title, padding=(10, 5, 10, 10))
            for idx, (value, title) in enumerate(values):
                set_value('Boolean', value, True)
                bttn = ttk.Checkbutton(frame, text=title, command=self._update,
                                    variable=self._vars[value])
                bttn.grid(row=idx % 2, column=idx - (idx % 2), sticky="nw")
            frame.pack(side='left', padx=10, pady=10)

        rframe = ttk.Frame(frame)
        rframe.pack(side='bottom', expand=True)

        assert len(self.sname) == 2
        set_value('String', 'all', 'all')
        radio_widget(rframe, title=_('Played Games'), name='all',
                     values=zip(('all', 'cur', ), self.sname))

        assert len(self.dname) == 4
        set_value('String', 'dur', 'week')
        radio_widget(rframe, title=_('Time Period'), name='dur',
                     values=zip(('week', 'month', 'year', 'all', ), self.dname))

        assert len(self.cname) == 3
        check_widget(rframe, title=_('Show Graphs'),
                   values=zip(('play', 'won', 'avg', ), self.cname))

    def _create_chart(self, *arg):
        """
        _create_chart() -> None

        Create the graph background, captions, and key.
        """
        if len(self.__items) > 0:
            return

        # Place captions and draw borders for chart
        self.canvas.create_rectangle(self.__lm, self.__bm, self.__rm - 4,
                                     self.__tm, fill=COLORPALLETE[4])
        self.__title = self.canvas.create_text(self.__lm, self.__tm,
                                               anchor='s', text=self.tname[0])
        self.canvas.create_text(self.__rm, self.__tm, anchor='s',
                                text=self.tname[1])

        self.update()

    def _update(self, *args):
        """
        update() -> None

        Update the chart with current results selection. Call parent
        **ProgressionFormatter** for progress results. Call scale horz, vert to
        set the scale for results. Call results to draw the graph.
        """
        if self.__items:
            self.canvas.delete(*self.__items)
        self.__items = []

        # Init sizers
        result = self._getResults(self._vars['dur'].get(),
                                  self._vars['all'].get())
        rowhigh = len(result) - 1
        width, height = self.__cw - 2 * self.__lm, self.__ch - 2 * self.__tm
        # Draw chart
        self.__vert_scale(result, width / rowhigh)
        self.__horz_scale(result, height / 5)
        self.__draw_results(result, width / rowhigh, height / 5)

    def __vert_scale(self, result, delta):
        """
        __vert_scale(result:seq(seq(text, played, won) ...), delta:int) -> None

        Draw the vertical scale on the graph.
        """
        x = self.__lm
        last_text = ''
        for text, played, won in result:
            if text is not None and last_text != text:
                self.__items.append(self.canvas.create_line(  # Full V-line
                                x, self.__bm, x, self.__tm, stipple='gray50'))
                self.__items.append(self.canvas.create_text(x,
                                    self.__bm + self.__th / 2, anchor='n',
                                    text=text))
                last_text = text
            x += delta

    def __horz_scale(self, result, delta):
        """
        __horz_scale(result:seq(seq(text, played, won) ...), delta:int)
         -> None

        Draw the horizontal scales on the graph.
        """
        self.__gdelta = max([i[1] for i in result]) / 5 + 1
        avgmark, cntmark = 0, 0

        for y in range(self.__bm, self.__tm, -delta):
            self.__items.append(self.canvas.create_line(     # Full H-line
                         self.__lm, y, self.__rm, y, stipple='gray50'))
            self.__items.append(self.canvas.create_text(     # Left Games
                                self.__lm - self.__th / 2, y,
                                anchor='e', text=cntmark))
            self.__items.append(self.canvas.create_text(     # Right Average
                                self.__rm + self.__th / 2, y,
                                anchor='w', text=avgmark))
            cntmark += self.__gdelta
            avgmark += 20

    def __draw_results(self, result, dx_, dy_):
        """
        __draw_results(result:seq(seq(text, played, won) ...), dx:int, dy:int)
         -> None

        Draw the actual stat on the graph.
        """
        gres, ares = float(dy_) / self.__gdelta, float(dy_) / 20
        pcoords, wcoords, acoords = [], [], []

        # Calculate graph points
        x = self.__lm
        for text, play, won in result:
            pcoords += [x, self.__bm - gres * play]
            wcoords += [x, self.__bm - gres * won]
            acoords += [x, self.__bm - ares * (100 * won / play
                                                 if play > 0 else 0)]
            x += dx_

        # Draw graph points
        if self._vars['play'].get():
            self.__items.append(self.canvas.create_line(fill=COLORPALLETE[0],
                                                        width=3, *pcoords))
        if self._vars['won'].get():
            self.__items.append(self.canvas.create_line(fill=COLORPALLETE[1],
                                                        width=3, *wcoords))
        if self._vars['avg'].get():
            self.__items.append(self.canvas.create_line(fill=COLORPALLETE[2],
                                                        width=3, *acoords))


class StatsDialog(tkSimpleDialog.Dialog):
    """
    Display current stats log for session and all games.
    """
    mode = -1

    def __init__(self, parent, player, gameid):
        """
        __init__(parent:Canvas, title:str, gameid:int) -> None

        Set game and player.
        """
        self.__gameid = gameid
        self.__player = player or _('Demo games')
        self.notebook = None
        self.__tabs = []

        style = ttk.Style(parent)
        self.tkfont = tkFont.Font(parent, style.lookup('.',  'font'))
        self.tkfont_ls = self.tkfont.metrics()['linespace']
        self.tkheadfont = tkFont.Font(parent, style.lookup('Heading', 'font'))

        tkSimpleDialog.Dialog.__init__(self, parent, _('Game Logs'))

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Create body of Stats.
        """
        notebook = ttk.Notebook(parent)
        notebook.pack(expand=True, fill='both', padx=10, pady=10)

        self.__tabs = []

        full_frame = _LogFrame(self, notebook, True)
        notebook.add(full_frame, text=_('Full log'))
        self.__tabs.append(full_frame._w)

        session_frame = _LogFrame(self, notebook, False)
        notebook.add(session_frame, text=_('Session log'))
        self.__tabs.append(session_frame._w)

        self.notebook = notebook

    def buttonbox(self):
        """
        buttonbox() -> None

        Set buttons for Save and Cancel, Reset. Call ok, cancel, or reset method
        when respective button selected.
        """
        box = ttk.Frame(self)

        select_widget = ttk.Button(box, text=_('Save Log'), width=10,
                                   command=self.ok)
        select_widget.pack(side=vcnst.LEFT, padx=PAD.x, pady=PAD.Y)

        cancel_widget = ttk.Button(box, text=_('Cancel'), width=10,
                                   command=self.cancel, default=vcnst.ACTIVE)
        cancel_widget.pack(side=vcnst.LEFT, padx=PAD.x, pady=PAD.Y)

        reset_widget = ttk.Button(box, text=_('Reset'), width=10,
                                   command=self._reset)
        reset_widget.pack(side=vcnst.LEFT, padx=PAD.x, pady=PAD.Y)

        self.bind('<Return>', self.cancel)
        self.bind('<Escape>', self.cancel)

        box.pack()

    def apply(self):
        """
        apply() -> None

        Set **self.mode** value depending on tab selected.
        """
        index = self.__tabs.index(self.notebook.select())
        assert index in [0, 1]
        self.mode = 203 if index == 0 else 204

    def _reset(self):
        """
        reset() -> None

        Set **self.mode** value depending on tab selected. Destroy dialog.
        """
        index = self.__tabs.index(self.notebook.select())
        assert index in [0, 1]
        self.mode = 301 if index == 0 else 302
        self.destroy()


class _LogFrame(ttk.Frame, LogFormatter, object):
    """
    Show Statistics Log frame
    """
    COLUMNS = ('#0', 'gamenumber', 'date', 'status')
    tname = _('Game'), _('Game number'), _('Started at'), _('Status')
    MAX_ROWS = 999
    __tabs = None
    _items = {}

    def __init__(self, dialog, parent, sessions='all'):
        """
        __init__(parent:Canvas, title:str, gameid:int) -> None

        Set list view for log data.
        """
        super(_LogFrame, self).__init__(parent)
        self.dialog = dialog
        self.__sessions = sessions
        self.__tree = ttk.Treeview(self, columns=self.COLUMNS[1:],
                                 selectmode='browse')
        self.__tree.grid(row=0, column=0)
        vsb = ttk.Scrollbar(self, command=self.__tree.yview)
        vsb.grid(row=0, column=1, sticky=vcnst.STICKY_NS)
        self.__tree.config(yscrollcommand=vsb.set)
        self.__create_header()
        self.pack(side=vcnst.TOP, expand=True, padx=10, pady=10)
        self.rowconfigure(0, weight=1)

        self.__tree.bind('<Map>', self.__populate)

    def __create_header(self):
        """
        self.__createHeader(column:str) => None

        Size columns and set header for __tree.
        """
        if self.__tabs is None:
            self.__tabs = [300]
            self.__tabs.extend(self.dialog.tkheadfont.measure(t) + 8
                               for t in self.tname[1:])

        for i, (col, ttl) in enumerate(zip(self.COLUMNS, self.tname)):
            self.__tree.column(col, width=self.__tabs[i], anchor='e')
            self.__tree.heading(col, text=ttl,
                                      command=lambda c=col: self.__setSort(c))

    def __populate(self, *args):
        """
        self.__populate(*args) => None

        Populate __tree with StatsFormatter data.
        """
        if len(self._items) > 0:
            return
        for row, result in enumerate(self.getLog(all_=self.__sessions)):
            index = self.__tree.insert('', 'end', text=result[0],
                                    values=result[1:-2])
            self._items[index] = None
            if row + 1 > self.MAX_ROWS:
                break